/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.invIn.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.invIn.entity.InvIn;
import vip.xiaonuo.modular.invIn.mapper.InvInMapper;
import vip.xiaonuo.modular.invIn.param.InvInParam;
import vip.xiaonuo.modular.invIn.result.invInResult;
import vip.xiaonuo.modular.invIn.service.InvInService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.modular.invdetail.entity.InvDetail;
import vip.xiaonuo.modular.invdetail.mapper.InvDetailMapper;
import vip.xiaonuo.modular.invdetail.param.InvDetailParam;
import vip.xiaonuo.modular.invdetail.service.InvDetailService;
import vip.xiaonuo.modular.stockbalance.entity.StockBalance;
import vip.xiaonuo.modular.stockbalance.param.StockBalanceParam;
import vip.xiaonuo.modular.stockbalance.service.StockBalanceService;
import vip.xiaonuo.util.AutoCode;
import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 入库表service接口实现类
 *
 * @author wz
 * @date 2022-08-22 16:46:42
 */
@Service
public class InvInServiceImpl extends ServiceImpl<InvInMapper, InvIn> implements InvInService {

    @Resource
    private InvDetailService invDetailService;

    @Resource
    private StockBalanceService stockBalanceService;

    @Override
    public PageResult<invInResult> page(InvInParam invInParam) {
        QueryWrapper<invInResult> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(invInParam)) {
            queryWrapper.lambda().eq(InvIn::getCategory, 1);
            // 根据编号 查询
            if (ObjectUtil.isNotEmpty(invInParam.getCode())) {
                queryWrapper.lambda().eq(InvIn::getCode, invInParam.getCode());
            }

            // 根据入库类型 查询
            if (ObjectUtil.isNotEmpty(invInParam.getInTypes())) {
                String[] inTypeList = invInParam.getInTypes().split(",");
                queryWrapper.lambda().in(InvIn::getInType, inTypeList);
            }
            // 根据入库仓库 查询
            if (ObjectUtil.isNotEmpty(invInParam.getWarHouId())) {
                queryWrapper.lambda().like(InvIn::getWarHouId, invInParam.getWarHouId());
            }
            // 根据备注 查询
            if (ObjectUtil.isNotEmpty(invInParam.getRemarks())) {
                queryWrapper.lambda().like(InvIn::getRemarks, invInParam.getRemarks());
            }
            // 根据入库时间 查询
            if (ObjectUtil.isNotEmpty(invInParam.getTime())) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                Date date = new Date();
                try {
                    date = sdf.parse(invInParam.getTime());
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                //得到日历
                Calendar calendar = Calendar.getInstance();
                //把当前时间赋给日历
                calendar.setTime(date);
                queryWrapper.lambda().ge(InvIn::getTime, sdf.format(calendar.getTime()));
                //设置为后一天
                calendar.add(Calendar.DAY_OF_MONTH, +1);
                queryWrapper.lambda().lt(InvIn::getTime, sdf.format(calendar.getTime()));
            }

        }
        //进行二次数据处理
        //取到查到的数据
        Page<invInResult> page=this.baseMapper.page(PageFactory.defaultPage(),queryWrapper);
        /*
         * ===============================================处理数据的准备工作 start ======================================
         */
        //取到所需要的数据
        List<InvDetail> invDetailList = invDetailService.list();
        Map<Long, List<InvDetail>> invDetailGroupByInvId = invDetailList.stream().collect(Collectors.groupingBy(InvDetail::getInvId));
        /*
         * ===============================================处理数据的准备工作 end ======================================
         */
        /*
         * ===============================================给入库明细list赋值 start ======================================
         */
        page.getRecords().forEach(item -> {
                    Long id = item.getId();
                    if (ObjectUtil.isEmpty(id)) {
                        return;
                    }
                    List<InvDetail> invDetails = invDetailGroupByInvId.get(item.getId());
                    if (ObjectUtil.isEmpty(invDetails)) {
                        return;
                    }
                    item.setInvDetailList(invDetails);
                }
        );
        /*
         * ===============================================给入库明细list赋值 end ======================================
         */
        return new PageResult<>(page);
    }

    @Override
    public List<InvIn> list(InvInParam invInParam) {
        return this.list();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(InvInParam invInParam) {
        //添加  为空校验
        checkParam(invInParam, false);
        /*
         * =======================================入库逻辑 start =====================================
         */
        if (ObjectUtil.isEmpty(invInParam.getCode())) {
            //表名称前加入一个空格 用区分入库还是出库   加了空格是入库
            invInParam.setCode(AutoCode.getCodeByService(" dw_inv", this.getClass(), 0));
        }
        InvIn invIn = new InvIn();
        BeanUtil.copyProperties(invInParam, invIn);
        //1 :入库
        invIn.setCategory(1);
        this.save(invIn);
        /*
         * =======================================入库逻辑 end =====================================
         */


        /*
         * =======================================库存余额逻辑 start =====================================
         */
        List<StockBalanceParam> stockBalanceParamList=new ArrayList<>();
        invInParam.getInvDetailList().forEach(invDetail -> {
            StockBalanceParam stockBalanceParam = new StockBalanceParam();
            stockBalanceParam.setWarHouId(invInParam.getWarHouId());
            stockBalanceParam.setProId(invDetail.getProId());
            stockBalanceParam.setStoNum(invDetail.getNum());
            stockBalanceParamList.add(stockBalanceParam);
        });
        //添加库存余额
        addStockBalance(stockBalanceParamList,invInParam);

        /*
         * =======================================库存余额逻辑 end =====================================
         */

        /*
         * =======================================库存明细逻辑 start =====================================
         */
        invInParam.getInvDetailList().forEach(invDetail -> {
            invDetail.setInvId(invIn.getId());
            invDetail.setWarHouId(invIn.getWarHouId());
        });
        //添加库存明细
        invDetailService.saveBatch(invInParam.getInvDetailList());
        /*
         * =======================================库存明细逻辑 end =====================================
         */
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<InvInParam> invInParamList) {
        List<Long> deleteInvDetail=new ArrayList<>();
        List<StockBalanceParam> deleteStock=new ArrayList<>();
        List<Long> deleteInv=new ArrayList<>();
        invInParamList.forEach(invInParam -> {
            /*
             * =======================================删除库存明细 start =====================================
             */
            QueryWrapper<InvDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(InvDetail::getInvId, invInParam.getId());
            List<InvDetail> invDetailList = invDetailService.list(queryWrapper);
            invDetailList.forEach(invDetail -> {
                /*
                 * =======================================删除库存余额逻辑 start =====================================
                 */

                //修改根据仓库id和产品id修改仓库余额
                StockBalanceParam stockBalanceParam = new StockBalanceParam();
                stockBalanceParam.setWarHouId(invDetail.getWarHouId());
                stockBalanceParam.setProId(invDetail.getProId());
                stockBalanceParam.setStoNum(invDetail.getNum());
                deleteStock.add(stockBalanceParam);
                /*
                 * =======================================库存余额逻辑 end =====================================
                 */
                //删除该条入库明细
                deleteInvDetail.add(invDetail.getId());
            });
            /*
             * =======================================删除库存明细 end =====================================
             */
            //最后删除入库单
            deleteInv.add(invInParam.getId());
        });
        this.removeByIds(deleteInv);
        deleteStockBalance(deleteStock);
        invDetailService.removeByIds(deleteInvDetail);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(InvInParam invInParam) {
        //添加  唯一编码校验
        checkParam(invInParam, true);
        //如果编码为空，手动添加编码
        if (ObjectUtil.isEmpty(invInParam.getCode())) {
            throw new ServiceException(8, "编号不能为空，请输入编号");
        }
        InvIn invIn = this.getById(invInParam.getId());
        BeanUtil.copyProperties(invInParam,invIn);
        this.updateById(invIn);

        /*
         * =======================================修改库存明细和库存余额 start =====================================
         */
        List<InvDetail> invDetailList = invInParam.getInvDetailList();
        //取得数据库中的该入库单的所有明细
        LambdaQueryWrapper<InvDetail> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InvDetail::getInvId, invInParam.getId());
        List<InvDetail> invDetails = invDetailService.list(lqw);
        Map<Long,InvDetail> invDetailMap=invDetails.stream().collect(Collectors.toMap(InvDetail::getId,a->a,(k1,k2)->k1));
        List<Long> invDetailIds = new ArrayList<>();
        List<StockBalanceParam> addStock=new ArrayList<>();
        List<StockBalanceParam> deleteStock=new ArrayList<>();
        List<InvDetail> addInvDetails=new ArrayList<>();
        List<InvDetail> editInvDetailList=new ArrayList<>();
        List<Long> deleteInvDetailList=new ArrayList<>();
        invDetails.forEach(invDetail->{
            invDetailIds.add(invDetail.getId());
        });
        Long invInId = invInParam.getId();
        for (InvDetail invDetail : invDetailList
        ) {
            invDetail.setInvId(invInId);
            //修改明细里面的仓库id
            invDetail.setWarHouId(invInParam.getWarHouId());
            //没有明细id的进行添加
            if (ObjectUtil.isEmpty(invDetail.getId())) {
                // 添加库存明细
                addInvDetails.add(invDetail);
                // 添加库存余额
                StockBalanceParam stockBalanceParam = new StockBalanceParam();
                stockBalanceParam.setWarHouId(invInParam.getWarHouId());
                stockBalanceParam.setProId(invDetail.getProId());
                stockBalanceParam.setStoNum(invDetail.getNum());
                addStock.add(stockBalanceParam);
            }
            //已有明细id的进行修改
            if (ObjectUtil.isNotEmpty(invDetail.getId())) {
                invDetailIds.remove(invDetail.getId());
                InvDetail oldInvDetail=invDetailMap.get(invDetail.getId());
                //删除原产品明细下的仓库余额
                StockBalanceParam stockBalanceParam = new StockBalanceParam();
                stockBalanceParam.setWarHouId(invInParam.getWarHouId());
                stockBalanceParam.setProId(invDetail.getProId());
                stockBalanceParam.setStoNum(invDetail.getNum());
                addStock.add(stockBalanceParam);
                StockBalanceParam stockBalanceParamOld = new StockBalanceParam();
                stockBalanceParamOld.setWarHouId(oldInvDetail.getWarHouId());
                stockBalanceParamOld.setProId(oldInvDetail.getProId());
                stockBalanceParamOld.setStoNum(oldInvDetail.getNum());
                deleteStock.add(stockBalanceParamOld);
                editInvDetailList.add(invDetail);
                //增加现在的仓库余额
                invDetail.setInvId(invInParam.getId());
            }
        }
        //剩下的进行删除
        for (Long invDetailId : invDetailIds
        ) {
            InvDetail invDetail = invDetailService.getById(invDetailId);
            StockBalanceParam stockBalanceParam = new StockBalanceParam();
            stockBalanceParam.setWarHouId(invDetail.getWarHouId());
            stockBalanceParam.setProId(invDetail.getProId());
            stockBalanceParam.setStoNum(invDetail.getNum());
            deleteStock.add(stockBalanceParam);
            deleteInvDetailList.add(invDetailId);
        }
        addStockBalance(addStock,invInParam);
        deleteStockBalance(deleteStock);
        invDetailService.saveBatch(addInvDetails);
        invDetailService.updateBatchById(editInvDetailList);
        invDetailService.removeByIds(deleteInvDetailList);
        /*
         * =======================================修改库存明细和库存余额 end =====================================
         */


    }

    @Override
    public InvIn detail(InvInParam invInParam) {
        return this.queryInvIn(invInParam);
    }

    /**
     * 获取入库表
     *
     * @author gjx
     * @date 2022-08-22 16:46:42
     */
    private InvIn queryInvIn(InvInParam invInParam) {
        InvIn invIn = this.getById(invInParam.getId());
        if (ObjectUtil.isNull(invIn)) {
            throw new ServiceException(1, "此数据不存在");
        }
        return invIn;
    }

    @Override
    public void export(InvInParam invInParam) {
        List<InvIn> list = this.list(invInParam);
        PoiUtil.exportExcelWithStream("SnowyInvIn.xls", InvIn.class, list);
    }
    private void checkParam(InvInParam invInParam, boolean isExcludeSelf) {

        //校验数据是否为空
        if (ObjectUtil.isEmpty(invInParam.getInType())) {
            throw new ServiceException(6, "入库类型不能为空");
        }
        if (ObjectUtil.isEmpty(invInParam.getInvDetailList())) {
            throw new ServiceException(3, "产品不能为空，请添加产品");
        }
        if (ObjectUtil.isEmpty(invInParam.getTime())) {
            throw new ServiceException(7, "入库时间不能为空");
        }
        for (InvDetail invDetail : invInParam.getInvDetailList()) {
            if (ObjectUtil.isEmpty(invDetail.getProId())) {
                throw new ServiceException(3, "产品不能为空，请添加产品");
            }
            if (ObjectUtil.isEmpty(invDetail.getNum()) || invDetail.getNum() <= 0) {
                throw new ServiceException(4, "入库数量不能为空并且必须大于零，请重新输入");
            }
        }
        LambdaQueryWrapper<InvIn> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //如果是编辑需要去除自己
        if (isExcludeSelf) {
            lambdaQueryWrapper.ne(InvIn::getId, invInParam.getId());
        }
        lambdaQueryWrapper.eq(InvIn::getCode, invInParam.getCode());
        int count = this.count(lambdaQueryWrapper);
        if (count >= 1) {
            throw new ServiceException(2, "唯一编号已存在");
        }
    }
    //根据 明细删除库存余额
    private void deleteStockBalance(List<StockBalanceParam> stockBalanceParamList) {
        stockBalanceService.deleteStockBalance(stockBalanceParamList);
    }

    //根据 明细添加库存余额
    private void addStockBalance(List<StockBalanceParam> stockBalanceParams,InvInParam invInParam) {
        stockBalanceService.addStockBalance(stockBalanceParams);
    }

}
